package com.seed.core.builder.declare;

import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.query.QueryTable;
import com.seed.core.builder.pojo.Join1;
import com.seed.core.builder.pojo.OnCondition1;
import com.seed.core.builder.pojo.Column1;
import com.seed.core.builder.pojo.Table1;
import com.seed.core.builder.query.FillBuilder;
import com.seed.core.column.Column;
import com.seed.core.enumeration.PropertyType;
import com.seed.core.pojo.Join;
import com.seed.core.pojo.seed.HasManys;
import com.seed.core.pojo.seed.Relation;
import com.seed.core.pojo.seed.Seed;
import com.seed.core.query.SeedFill;
import com.seed.core.query.pojo.Declared;
import com.seed.util.Join1Kit;
import com.seed.util.SeedKit;
import com.seed.util.StrKit;

import java.util.LinkedHashMap;
import java.util.Map;

public class DeclaredWrapper {

    private final Map<String, Column1> selects = new LinkedHashMap<>(); // 选择列对象
    private final Map<String, Join1> joins = new LinkedHashMap<>(); // 表关联对象
    private final Map<String, FillBuilder> fills = new LinkedHashMap<>(); // 数据填充对象

    public DeclaredWrapper(Seed selfSeed, Map<String, Declared> declared) {
        init(null, selfSeed, declared);
    }

    private void init(String basePath, Seed selfSeed, Map<String, Declared> declared) {
        String selfTableAlias = StrKit.selfTableAlias(basePath);
        Table1 table1 = new Table1(selfSeed.getTableName()).as(selfTableAlias);
        for(Map.Entry<String, Declared> entry: declared.entrySet()) {
            String crossOrColumn = entry.getKey();
            String finalPath = StrKit.concat(basePath, crossOrColumn);
            Declared value = entry.getValue();
            PropertyType propertyType = value.getType();
            switch (propertyType) {
                case none, asterisk -> {
                    Map<String, Column> columns = selfSeed.getColumns();
                    for (Column column: columns.values()) {
                        String columName = column.getName();
                        String finalColumn = StrKit.concat(basePath, columName);
                        String columnAlias = StrUtil.toCamelCase(finalColumn);
                        selects.putIfAbsent(finalColumn, new Column1(table1, columName, columnAlias));
                    }
                }
                case column -> {
                    String columnAlias = StrUtil.toCamelCase(finalPath);
                    selects.putIfAbsent(finalPath, new Column1(table1, crossOrColumn, columnAlias));
                }
                case hasOne, belongsTo -> {
                    Relation relation = (Relation) value.getProperty();
                    Join1 join1 = Join1Kit.buildJoin1(relation, basePath, crossOrColumn);
                    joins.putIfAbsent(finalPath, join1);
                    init(finalPath, relation.targetSeed(), value);
                }
                case hasMany, habtm -> {
                    Relation relation = (Relation) value.getProperty();
                    Seed targetSeed = relation.targetSeed();

                    Table1 selfTable1 = new Table1(relation.selfSeed().getTableName()).as(selfTableAlias);
                    String selfColumn = relation.inferSelfColumn();
                    String selfColumnPath = StrKit.concat(basePath, selfColumn);
                    String columnAlias = StrUtil.toCamelCase(selfColumnPath);
                    selects.putIfAbsent(selfColumnPath, new Column1(selfTable1, selfColumn, columnAlias));
//                    fills.put(finalPath, new SeedFill(basePath, crossOrColumn, (HasManys) relation, targetSeed, value));
                    FillBuilder builder = new FillBuilder(basePath, crossOrColumn, (HasManys) relation, targetSeed);
                    builder.declaredWrapper(new DeclaredWrapper(targetSeed, value));
                    fills.put(finalPath, builder);
                }
            }
        }
    }

    public Map<String, Column1> getSelects() {
        return selects;
    }

    public Map<String, Join1> getJoins() {
        return joins;
    }

    public Map<String, FillBuilder> getFills() {
        return fills;
    }
}
